<template>
	<a-tree
		:blockNode="true"
		:showIcon="true"
		:draggable="true"
		:tree-data="items"
		:load-data="load"
		:fieldNames="{ children: 'children', title: 'text', key: 'id' }"
		:checkable="multiple"
		:multiple="multiple"
		:expandedKeys="expanded"
		:selectedKeys="selected"
		:checkedKeys="selected"
		:loadedKeys="loadedKeys"
		@select="handleTreeNodeSelect"
		@rightClick="handleRightClick"
		@expand="handleExpand"
		@drop="handleDrop"
		@check="handleCheck"
	>
		<template #icon="node">
			<template v-if="hasSlot(`${node.nodeType}Icon`)">
				<slot :rowData="node" :name="`${node.nodeType}Icon`"></slot>
			</template>
			<template v-else>
				<TreeNodeIcon
					v-if="node.imagePath || node.cssClass || showDefaultIcon"
					:imagePath="node.imagePath"
					:cssClass="node.cssClass"
					:iconCustomCode="node.iconCustomCode"
					:iconScriptCode="node.iconScriptCode"
					:showDefaultIcon="showDefaultIcon"
				>
				</TreeNodeIcon>
			</template>
		</template>
		<template #title="node">
			<template v-if="hasSlot(node.nodeType)">
				<slot
					:rowData="node"
					:name="node.nodeType"
					:actions="{ handleValueChange, handleContextMenuClick }"
				></slot>
			</template>
			<TreeNodeTitle
				v-else
				:class="node.class"
				:textCustomCode="node.textCustomCode"
				:textScriptCode="node.textScriptCode"
				:html="node.html"
				:text="node.text"
				:tooltip="node.tooltip"
				:allowEditText="node.allowEditText"
				:contextMenus="node.contextMenus"
				:counterMode="node.counterMode"
				:count="counterData?.[node.counterId]"
				@value-change="(value: string) => handleValueChange(node, value)"
				@context-menu-item-click="(args: any) => handleContextMenuClick(node, args)"
			>
			</TreeNodeTitle>
		</template>
	</a-tree>
</template>

<script setup lang="ts">
import { treeProps } from './tree';
import TreeNodeIcon from './components/tree-node-icon.vue';
import TreeNodeTitle from './components/tree-node-title.vue';
import { Ref } from 'vue';
import { IParam } from '@/core';
const props = defineProps(treeProps);
const emit = defineEmits<{
	(name: 'selectionChange', selections: IParam[]): void;
	(name: 'expandChange', expandedKeys: string[]): void;
	(name: 'valueChange', node: IParam): void;
	(name: 'contextMenuItemClick', node: IParam, args: IParam): void;
}>();

let expanded: Ref<string[]> = computed(() => {
	return props.expandedKeys;
});
// 加载完成节点
let loadedKeys: Ref<string[]> = computed(() => {
	return props.loadedKeys;
});

let selected: Ref<string[]> = computed(() => {
	return props.selectedKeys;
});

// 处理树节点选中
const handleTreeNodeSelect = (
	selectedKeys: (string | number)[],
	{ selectedNodes }: { selectedNodes: IParam[] }
) => {
	emit('selectionChange', selectedNodes);
};
const handleExpand = (expandedKeys: (string | number)[], $event: any) => {
	emit('expandChange', expandedKeys as string[]);
};
// 处理右键点击
const handleRightClick = ($event: any) => {
	console.log('树右键:', $event);
};
// 处理复选框选中
const handleCheck = (
	checkedKeys:
		| (string | number)[]
		| { checked: (string | number)[]; halfChecked: (string | number)[] },
	{ checkedNodes }: { checkedNodes: IParam[] }
) => {
	emit('selectionChange', checkedNodes);
};

// 查找对应节点数据
const loop = (data: IParam[], id: string, callback: any) => {
	data.forEach((item, index) => {
		if (item.id === id) {
			return callback(item, index, data);
		}
		if (item.children) {
			return loop(item.children, id, callback);
		}
	});
};

// 处理值改变
const handleValueChange = (node: IParam, value: string) => {
	loop(props.items, node.id, (item: IParam, index: number, data: IParam[]) => {
		Object.assign(item, { text: value });
		emit('valueChange', item);
	});
};

// 处理拖拽
const handleDrop = ({
	dragNode,
	node: dropNode,
	dropPosition: position,
	dropToGap,
}: {
	dragNode: IParam;
	node: IParam;
	dropPosition: number;
	dropToGap: boolean;
}) => {
	let allowDrag = false;
	let allowDrop = false;
	if (dragNode.allowDrag || dragNode.allowOrder) {
		allowDrag = true;
	}
	if (dropNode.allowDrop || dropNode.allowOrder) {
		allowDrop = true;
	}
	if (allowDrag && allowDrop) {
		const data: IParam[] = props.items;
		const dropId = dropNode.id;
		const dragId = dragNode.id;
		const dropPos = dropNode.pos.split('-');
		const dropPosition = position - Number(dropPos[dropPos.length - 1]);
		let dragObj: IParam = {};
		loop(data, dragId, (item: IParam, index: number, arr: IParam[]) => {
			arr.splice(index, 1);
			dragObj = item;
		});
		if (!dropToGap) {
			loop(data, dropId, (item: IParam) => {
				item.children = item.children || [];
				item.children.unshift(dragObj);
			});
		} else if (
			dropNode.children?.length > 0 &&
			dropNode.expanded &&
			dropPosition === 1
		) {
			loop(data, dropId, (item: IParam) => {
				item.children = item.children || [];
				item.children.unshift(dragObj);
			});
		} else {
			let ar: IParam[] = [];
			let i = 0;
			loop(data, dropId, (item: IParam, index: number, arr: IParam[]) => {
				ar = arr;
				i = index;
			});
			if (dropPosition === -1) {
				ar.splice(i, 0, dragObj);
			} else {
				ar.splice(i + 1, 0, dragObj);
			}
		}
	}
};

// 树上下文菜单点击
const handleContextMenuClick = (node: IParam, args: any) => {
	emit('contextMenuItemClick', node, args);
};

const hasSlot = (name: string) => {
	return !!useSlots()?.[name];
};
</script>
